package nl.weeaboo.sh.view;

import java.awt.event.KeyEvent;

import javax.media.opengl.GL;

import nl.weeaboo.game.gl.GLImage;
import nl.weeaboo.game.gl.GLManager;
import nl.weeaboo.game.gl.ScreenShot;
import nl.weeaboo.game.input.UserInput;
import nl.weeaboo.game.text.TextRenderer;
import nl.weeaboo.sh.ComboCollector;
import nl.weeaboo.sh.Game;
import nl.weeaboo.sh.GameFrame;
import nl.weeaboo.sh.level.Level;
import nl.weeaboo.sh.level.LevelMenu;
import nl.weeaboo.sh.level.MainMenu;
import nl.weeaboo.sh.objects.Boss;
import nl.weeaboo.sh.objects.Player;
import timon.common.StringUtil;

public class OSD {

	public static final float screenshotFadeInc = .1f;
	
	protected Game game;
	protected Level level;
	
	private GLImage bgI;
	private GLImage bossBgI;
	private GLImage lifebarI;
	private GLImage magicbarI;
	private GLImage numbersI[];
		
	private int fps;
	private float lifebarValue;
	private float magicbarValue;
	
	private int b_hp, b_maxHp, b_timeLeft;
	private float bossbarValue;
	private int bossOsdCooldown;
	
	private int menuSelection;
	private LevelMenu confirmCancelMenu;
	private Runnable confirmOkAction;
	
	private GLImage screenshot;
	private float screenshotFade;
	
	public OSD(Game game, Level level) {
		this.game = game;
		this.level = level;
		
		bgI = game.getImage("menu/osd.png#background", false);
		bossBgI = game.getImage("menu/osd.png#bossBackground", false);
		lifebarI = game.getImage("menu/osd.png#lifebar", false);
		magicbarI = game.getImage("menu/osd.png#magicbar", false);
		
		numbersI = new GLImage[11];
		for (int n = 0; n < 10; n++) {
			numbersI[n] = game.getImage("menu/osd.png#n" + n, false);
		}
		numbersI[10] = game.getImage("menu/osd.png#slash", false);		
	}
	
	//Functions
	public void update(UserInput input, float dt) {
		if (screenshot != null && screenshotFade < 1.0f) {
			screenshotFade += screenshotFadeInc;
		}
		
		Player player = level.getPlayer();
		if (lifebarValue != player.getHp()) {
			if (Math.abs(lifebarValue - player.getHp()) <= 0.05f) {
				lifebarValue = player.getHp();
			} else {
				lifebarValue += (player.getHp() - lifebarValue) / 10.0f;
			}
		}
		if (magicbarValue != player.getMagic()) {
			if (Math.abs(magicbarValue - player.getMagic()) <= 0.05f) {
				magicbarValue = player.getMagic();
			} else {
				magicbarValue += (player.getMagic() - magicbarValue) / 10.0f;
			}
		}
		
		GameFrame gf = game.getGameFrame();
		fps = Math.max(0, Math.min(60, Math.round(gf.getCurrentFPS())));
		
		Boss boss = level.getBoss();
		if (boss != null || bossOsdCooldown != 0) {			
			if (boss != null) {
				b_hp = boss.getHp();
				b_maxHp = boss.getMaxHp();
				b_timeLeft = boss.getTimeLeft();
				bossOsdCooldown = 60;
			} else {
				if (bossOsdCooldown > 0) bossOsdCooldown--;
	
				b_hp = 0;
				b_timeLeft = 0;
			}
			
			if (bossbarValue != b_hp) {
				if (Math.abs(bossbarValue - b_hp) <= 0.05f) {
					bossbarValue = b_hp;
				} else {
					bossbarValue += (b_hp - bossbarValue) / 10.0f;
				}
			}
		} else {
			bossbarValue = 0;			
		}
	}
	
	public void updateMenu(UserInput input, float dt) {
		LevelMenu menu = level.getMenu();
		if (menu == null) return;

		if (screenshot != null && screenshotFade < 1.0f) {
			screenshotFade += screenshotFadeInc;
		}

		if (input.consumeKey(KeyEvent.VK_UP)) {
			menuSelection--;
		} else if (input.consumeKey(KeyEvent.VK_DOWN)) {
			menuSelection++;
		}
		
		menuSelection = Math.max(0, Math.min(menu.getOptions().length-1, menuSelection));

		boolean exec = input.consumeKey(KeyEvent.VK_C) || input.consumeKey(KeyEvent.VK_ENTER);
		if (menu == LevelMenu.CONFIRM) {
			if (input.consumeKey(KeyEvent.VK_X)) {
				exec = true;
				menuSelection = 1;
			}
		}

		if (exec) {
			if (menu == LevelMenu.CONFIRM) {
				switch (menuSelection) {
				case 0:
					confirmOkAction.run();
					return;
				case 1:
					LevelMenu m = confirmCancelMenu;
					confirmCancelMenu = null;
					level.setMenu(m);
				return;
				}
			} else if (menu == LevelMenu.PAUSE) {
				switch (menuSelection) {
				case 0:
					level.setMenu(null);
					return;
				case 1:
					showConfirm(new Runnable() {
						public void run() {
							game.setLevel(new MainMenu(game));
						}
					});
					return;
				}
			}
		}
	}

	public void draw(GLManager glm, int w, int h) {
		if (game.config.getShowComboInfo()) {
			drawComboInfo(glm);
		}
		
		drawStats(glm);
		
		if (level.getMenu() != null) {
			drawMenu(glm);
		}
	}
		
	protected void drawMenu(GLManager glm) {
		GL gl = glm.getGL();
	
		if (screenshot == null) {
			ScreenShot s = ScreenShot.screenshot(glm, 800, 480, game.getWidth(), game.getHeight());
			int argb[] = s.getARGB();
			//argb = ScreenCapture.blur(rgba, s.width, s.height, 5);
			for (int n = 0; n < argb.length; n++) {
				int a = (argb[n]>>24) & 0xFF;
				int r = (argb[n]>>16) & 0xFF;
				int g = (argb[n]>> 8) & 0xFF;
				int b = (argb[n]    ) & 0xFF;
				
				r >>= 1;
				g >>= 1;
				b >>= 1;
				
				argb[n] = (a<<24)|(r<<16)|(g<<8)|(b);
			}
			
			screenshot = game.addGeneratedImage(argb, s.width, s.height, false);
		}
		
		glm.pushColor();
		glm.setColor(1, 1, 1, screenshotFade);
		screenshot.draw(glm);
		glm.popColor();
		
		/*
		glm.setTexture(null);
		glm.pushColor();
		glm.setColor(0, 0, 0, .75f);
		GLDraw.fillRect(gl, 0, 0, 800, 480);
		glm.popColor();
		*/		
		
		LevelMenu menu = level.getMenu();
		int ms = menuSelection;
		GLImage paused = game.getImage("menu/osd.png#paused", true);		
		paused.draw(glm, 400-paused.getWidth()/2, 120);

		String options[] = menu.getOptions();
		for (int n = 0; n < options.length; n++) {
			int ty = 280 + 60*n;			
			if (n == ms) {
				gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
				GLImage markI = game.getImage("menu/osd.png#o_mark", true);
				markI.draw(glm, 0, ty+30-5, 800, 15);
				gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
			}
			
			GLImage optionI = game.getImage("menu/osd.png#" + options[n]+(n == ms ? "S" : ""), true);
			optionI.draw(glm, 400-optionI.getWidth()/2, ty);
		}
	}
	
	protected void drawStats(GLManager glm) {
		Player player = level.getPlayer();
		
		bgI.draw(glm);
		
		lifebarI.draw(glm, 60, 0, Math.round(200f * lifebarValue / player.getMaxHp()), 24);
		magicbarI.draw(glm, 330, 0, Math.round(200f * magicbarValue / player.getMaxMagic()), 24);
				
		drawText(glm, String.format("%d/%d", player.getHp(), player.getMaxHp()), 240, 0, 10);
		drawText(glm, String.format("%d/%d", player.getMagic(), player.getMaxMagic()), 510, 0, 10);
		drawText(glm, String.format("%08d", 0), 690, 0, 10);
		drawText(glm, String.format("%02d", fps), 780, 0, 10);
		
		Boss boss = level.getBoss();
		if (boss != null || bossOsdCooldown != 0) {			
			glm.pushColor();
			if (boss == null && bossOsdCooldown >= 0) {
				glm.mixColor(1, 1, 1, Math.min(1f, bossOsdCooldown / 60f));
			}
			
			int y = 480-23;
			bossBgI.draw(glm, 0, y);
			lifebarI.draw(glm, 60, y, Math.round(600f * bossbarValue / b_maxHp), 24);

			drawText(glm, String.format("%d/%d", b_hp, b_maxHp), 640, y, 10);
			drawText(glm, String.format("%03d", b_timeLeft), 780, y, 10);
			
			glm.popColor();
		}		
	}
	
	protected void drawComboInfo(GLManager glm) {
		ComboCollector cc = level.getPlayer().getComboCollector();
		int keys[] = cc.getPressed();
		int keysL = cc.getPressedLength();
		
		StringBuilder sb = new StringBuilder();
		for (int n = 0; n < keysL; n++) {
			if (n > 0) sb.append(' ');
			
			String s;
			switch (keys[n]) {
			case KeyEvent.VK_UP:    s = "U"; break;
			case KeyEvent.VK_DOWN:  s = "D"; break;
			case KeyEvent.VK_LEFT:  s = "L"; break;
			case KeyEvent.VK_RIGHT: s = "R"; break;
			case KeyEvent.VK_Z:     s = "3"; break;
			case KeyEvent.VK_X:     s = "2"; break;
			case KeyEvent.VK_C:     s = "1"; break;
			default: s = Integer.toString(keys[n]);
			}
			sb.append(s);
		}
		
		TextRenderer tr = game.getImageStore().getTextRenderer(game.getDefaultFont());
		tr.drawString(glm, sb.toString(), 24, 40, 7);
	}
	
	protected void drawText(GLManager glm, String string, int x, int y, int spacing) {
		int letters[] = StringUtil.toUnicodeArray(string);
		
		x -= letters.length * spacing;
		for (int n = 0; n < letters.length; n++) {
			GLImage image = null;
			if (letters[n] >= '0' && letters[n] <= '9') {
				image = numbersI[letters[n]-'0'];
			} else if (letters[n] == '/') {
				image = numbersI[10];
			}
			
			if (image != null) image.draw(glm, x, y);

			x += spacing;
		}
	}
	
	protected void showConfirm(Runnable r) {
		confirmCancelMenu = level.getMenu();
		confirmOkAction = r;
		level.setMenu(LevelMenu.CONFIRM);
		menuSelection = 1;
	}
	
	//Getters
	public boolean isOpaque() { return screenshot != null && screenshotFade >= 1f; }
	
	//Setters
	public void onMenuChanged(LevelMenu oldMenu, LevelMenu newMenu) {
		menuSelection = 0;

		if (newMenu == null) {
			screenshot = null;
			screenshotFade = 0;			
		}		
	}
	
}
